1
|
|
|
/** |
2
|
|
|
* Translates a text and inserts the specified content into the |
3
|
|
|
* placeholders (if any). If no translation is available for the |
4
|
|
|
* text, the original text is used. |
5
|
|
|
* |
6
|
|
|
* @param {String} text |
|
|
|
|
7
|
|
|
* @param {String} [placeholderContent]* |
|
|
|
|
8
|
|
|
* @returns {String} |
9
|
|
|
*/ |
10
|
|
|
function t() |
11
|
|
|
{ |
12
|
|
|
return AppLocalize_Translator['Translate'].apply(AppLocalize_Translator, arguments); |
13
|
|
|
} |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* Used by the clientside strings collection to register |
17
|
|
|
* all translated strings. This is used to keep the code |
18
|
|
|
* as small as possible, by chaining the methods. |
19
|
|
|
*/ |
20
|
|
|
var AppLocalize_Translator = |
21
|
|
|
{ |
22
|
|
|
'strings':{}, |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* Adds a single translated string. |
26
|
|
|
* @param {String} name |
27
|
|
|
* @param {String} value |
28
|
|
|
*/ |
29
|
|
|
a:function(hash, text) |
30
|
|
|
{ |
31
|
|
|
this.strings[hash] = text; |
32
|
|
|
|
33
|
|
|
return this; |
34
|
|
|
}, |
35
|
|
|
|
36
|
|
|
Translate:function() |
37
|
|
|
{ |
38
|
|
|
var text = arguments[0]; |
39
|
|
|
var translated = text; |
40
|
|
|
var hash = hex_md5(text); |
41
|
|
|
|
42
|
|
|
if (typeof(this.strings[hash]) != 'undefined' && this.strings[hash] != null) { |
|
|
|
|
43
|
|
|
translated = this.strings[hash]; |
44
|
|
|
} |
45
|
|
|
|
46
|
|
|
if (arguments.length > 1) |
47
|
|
|
{ |
48
|
|
|
var args = arguments; |
49
|
|
|
args[0] = translated; |
50
|
|
|
translated = AppLocalize_Translator['sprintf'].apply(null, args); |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
return translated; |
54
|
|
|
}, |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* JS equivalent of the PHP sprintf function, used to format |
58
|
|
|
* strings and insert dynamic content into placeholders. |
59
|
|
|
* |
60
|
|
|
* @param {String} format |
61
|
|
|
* @param {String} [insertContent]* |
62
|
|
|
* @returns {String} |
63
|
|
|
*/ |
64
|
|
|
sprintf:function() |
65
|
|
|
{ |
66
|
|
|
// http://kevin.vanzonneveld.net |
67
|
|
|
// + original by: Ash Searle (http://hexmen.com/blog/) |
68
|
|
|
// + namespaced by: Michael White (http://getsprink.com) |
69
|
|
|
// + tweaked by: Jack |
70
|
|
|
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) |
71
|
|
|
// + input by: Paulo Freitas |
72
|
|
|
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) |
73
|
|
|
// + input by: Brett Zamir (http://brett-zamir.me) |
74
|
|
|
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) |
75
|
|
|
// + improved by: Dj |
76
|
|
|
// + improved by: Allidylls |
77
|
|
|
// * example 1: sprintf("%01.2f", 123.1); |
78
|
|
|
// * returns 1: 123.10 |
79
|
|
|
// * example 2: sprintf("[%10s]", 'monkey'); |
80
|
|
|
// * returns 2: '[ monkey]' |
81
|
|
|
// * example 3: sprintf("[%'#10s]", 'monkey'); |
82
|
|
|
// * returns 3: '[####monkey]' |
83
|
|
|
// * example 4: sprintf("%d", 123456789012345); |
84
|
|
|
// * returns 4: '123456789012345' |
85
|
|
|
var regex = /%%|%(\d+\$)?([-+\'#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuideEfFgG])/g; |
86
|
|
|
var a = arguments, |
87
|
|
|
i = 0, |
88
|
|
|
format = a[i++]; |
89
|
|
|
|
90
|
|
|
// pad() |
91
|
|
|
var pad = function (str, len, chr, leftJustify) { |
92
|
|
|
if (!chr) { |
93
|
|
|
chr = ' '; |
94
|
|
|
} |
95
|
|
|
var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr); |
96
|
|
|
return leftJustify ? str + padding : padding + str; |
97
|
|
|
}; |
98
|
|
|
|
99
|
|
|
// justify() |
100
|
|
|
var justify = function (value, prefix, leftJustify, minWidth, zeroPad, customPadChar) { |
101
|
|
|
var diff = minWidth - value.length; |
102
|
|
|
if (diff > 0) { |
103
|
|
|
if (leftJustify || !zeroPad) { |
104
|
|
|
value = pad(value, minWidth, customPadChar, leftJustify); |
105
|
|
|
} else { |
106
|
|
|
value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length); |
107
|
|
|
} |
108
|
|
|
} |
109
|
|
|
return value; |
110
|
|
|
}; |
111
|
|
|
|
112
|
|
|
// formatBaseX() |
113
|
|
|
var formatBaseX = function (value, base, prefix, leftJustify, minWidth, precision, zeroPad) { |
114
|
|
|
// Note: casts negative numbers to positive ones |
115
|
|
|
var number = value >>> 0; |
116
|
|
|
prefix = prefix && number && { |
117
|
|
|
'2': '0b', |
118
|
|
|
'8': '0', |
119
|
|
|
'16': '0x' |
120
|
|
|
}[base] || ''; |
121
|
|
|
value = prefix + pad(number.toString(base), precision || 0, '0', false); |
122
|
|
|
return justify(value, prefix, leftJustify, minWidth, zeroPad); |
123
|
|
|
}; |
124
|
|
|
|
125
|
|
|
// formatString() |
126
|
|
|
var formatString = function (value, leftJustify, minWidth, precision, zeroPad, customPadChar) { |
127
|
|
|
if (precision != null) { |
|
|
|
|
128
|
|
|
value = value.slice(0, precision); |
129
|
|
|
} |
130
|
|
|
return justify(value, '', leftJustify, minWidth, zeroPad, customPadChar); |
131
|
|
|
}; |
132
|
|
|
|
133
|
|
|
// doFormat() |
134
|
|
|
var doFormat = function (substring, valueIndex, flags, minWidth, _, precision, type) { |
135
|
|
|
var number; |
136
|
|
|
var prefix; |
137
|
|
|
var method; |
138
|
|
|
var textTransform; |
139
|
|
|
var value; |
140
|
|
|
|
141
|
|
|
if (substring == '%%') { |
142
|
|
|
return '%'; |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
// parse flags |
146
|
|
|
var leftJustify = false, |
147
|
|
|
positivePrefix = '', |
148
|
|
|
zeroPad = false, |
149
|
|
|
prefixBaseX = false, |
150
|
|
|
customPadChar = ' '; |
151
|
|
|
var flagsl = flags.length; |
152
|
|
|
for (var j = 0; flags && j < flagsl; j++) { |
153
|
|
|
switch (flags.charAt(j)) { |
154
|
|
|
case ' ': |
155
|
|
|
positivePrefix = ' '; |
156
|
|
|
break; |
157
|
|
|
case '+': |
158
|
|
|
positivePrefix = '+'; |
159
|
|
|
break; |
160
|
|
|
case '-': |
161
|
|
|
leftJustify = true; |
162
|
|
|
break; |
163
|
|
|
case "'": |
164
|
|
|
customPadChar = flags.charAt(j + 1); |
165
|
|
|
break; |
166
|
|
|
case '0': |
167
|
|
|
zeroPad = true; |
168
|
|
|
break; |
169
|
|
|
case '#': |
170
|
|
|
prefixBaseX = true; |
171
|
|
|
break; |
172
|
|
|
} |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
// parameters may be null, undefined, empty-string or real valued |
176
|
|
|
// we want to ignore null, undefined and empty-string values |
177
|
|
|
if (!minWidth) { |
178
|
|
|
minWidth = 0; |
179
|
|
|
} else if (minWidth == '*') { |
180
|
|
|
minWidth = +a[i++]; |
181
|
|
|
} else if (minWidth.charAt(0) == '*') { |
182
|
|
|
minWidth = +a[minWidth.slice(1, -1)]; |
183
|
|
|
} else { |
184
|
|
|
minWidth = +minWidth; |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
// Note: undocumented perl feature: |
188
|
|
|
if (minWidth < 0) { |
189
|
|
|
minWidth = -minWidth; |
190
|
|
|
leftJustify = true; |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
if (!isFinite(minWidth)) { |
194
|
|
|
throw new Error('sprintf: (minimum-)width must be finite'); |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
if (!precision) { |
198
|
|
|
precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : undefined; |
199
|
|
|
} else if (precision == '*') { |
200
|
|
|
precision = +a[i++]; |
201
|
|
|
} else if (precision.charAt(0) == '*') { |
202
|
|
|
precision = +a[precision.slice(1, -1)]; |
203
|
|
|
} else { |
204
|
|
|
precision = +precision; |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
// grab value using valueIndex if required? |
208
|
|
|
value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++]; |
209
|
|
|
|
210
|
|
|
switch (type) { |
211
|
|
|
case 's': |
212
|
|
|
return formatString(String(value), leftJustify, minWidth, precision, zeroPad, customPadChar); |
213
|
|
|
case 'c': |
214
|
|
|
return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad); |
215
|
|
|
case 'b': |
216
|
|
|
return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad); |
217
|
|
|
case 'o': |
218
|
|
|
return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad); |
219
|
|
|
case 'x': |
220
|
|
|
return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad); |
221
|
|
|
case 'X': |
222
|
|
|
return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad).toUpperCase(); |
223
|
|
|
case 'u': |
224
|
|
|
return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad); |
225
|
|
|
case 'i': |
226
|
|
|
case 'd': |
227
|
|
|
number = +value || 0; |
228
|
|
|
number = Math.round(number - number % 1); // Plain Math.round doesn't just truncate |
229
|
|
|
prefix = number < 0 ? '-' : positivePrefix; |
230
|
|
|
value = prefix + pad(String(Math.abs(number)), precision, '0', false); |
231
|
|
|
return justify(value, prefix, leftJustify, minWidth, zeroPad); |
232
|
|
|
case 'e': |
233
|
|
|
case 'E': |
234
|
|
|
case 'f': // Should handle locales (as per setlocale) |
235
|
|
|
case 'F': |
236
|
|
|
case 'g': |
237
|
|
|
case 'G': |
238
|
|
|
number = +value; |
239
|
|
|
prefix = number < 0 ? '-' : positivePrefix; |
240
|
|
|
method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())]; |
241
|
|
|
textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2]; |
242
|
|
|
value = prefix + Math.abs(number)[method](precision); |
243
|
|
|
return justify(value, prefix, leftJustify, minWidth, zeroPad)[textTransform](); |
244
|
|
|
default: |
245
|
|
|
return substring; |
246
|
|
|
} |
247
|
|
|
}; |
248
|
|
|
|
249
|
|
|
return format.replace(regex, doFormat); |
250
|
|
|
} |
251
|
|
|
}; |
252
|
|
|
|